//
//  main.swift
//  xmm64
//
//  Created by marcow on 4/11/19.
//  Copyright © 2019 marcow. All rights reserved.
//

import Foundation

var isFloat = false
// 十进制转为二进制字符串
// TODO: 负数处理
func decTobin(_ number:Int) -> String {
    if number == 0 {
        return "0"
    }
    var num = number
    var str = ""
    while num > 0 {
        str = "\(num % 2)" + str
        num /= 2
    }
    return str
}

// 输入浮点寄存器的值，转换为 Double
func xmm64(_ input: Int, isNegative:Bool = false) -> Double {
    var power = (input >> (4*13)) - 0x3FF
    var result = decTobin(input & 0x000FFFFFFFFFFFFF)
    if result.count < 52 {
        result.insert(contentsOf: String(repeating: "0", count: 52 - result.count), at: result.startIndex)
    }
    if isFloat {
        power = (input >> 23) - 127
        result = decTobin(input & 0x007fffff)
        if result.count < 23 {
            result.insert(contentsOf: String(repeating: "0", count: 23 - result.count), at: result.startIndex)
        }
    }
    if power >= 0 {
        if power > result.count {
            result = "1" + result + String(repeating: "0", count: power - result.count) + ".0"
        } else if power < result.count {
            let index = result.index(result.startIndex, offsetBy: power)
            result.insert(".", at: index)
            result = "1" + result
        } else {
            result = "1" + result + ".0"
        }
    }else {
        result = "1" + result
        result = "0." + String(repeating: "0", count: power * -1 - 1) + result
    }
    let dotString = result.split(separator: ".")[1]
    var dot = 0.0
    for (index, aBit) in dotString.enumerated() {
        if aBit == "1" {
            dot += Double(1.0 / pow(Double(2.0), Double(index + 1)))
        }
    }
    let intsString = result.split(separator: ".")[0]
    var intBin = 0.0
    for (index, aInt) in intsString.enumerated() {
        if aInt == "1" {
            intBin += Double(pow(Double(2.0), Double(intsString.count - index - 1)))
        }
    }
    if isNegative {
        return (intBin + dot) * -1
    } else {
        return intBin + dot
    }
    
    
}

// 参考：http://www.ruanyifeng.com/blog/2010/06/ieee_floating-point_representation.html
// TODO: 按参考更正？
let args = CommandLine.arguments
let negative: [Character] = ["8", "9", "a", "A", "b", "B", "c", "C", "d", "D", "e", "E", "f", "F"]
let replace: [Character]  = ["0", "1", "2", "2", "3", "3", "4", "4", "5", "5", "6", "6", "7", "7"]
var multiple = 1.0;
for (index ,arg) in args.enumerated() {
    var isNegative = false
    if index == 0 {
        continue
    }
    // 计算 color
    if arg == "-c" {
        multiple = 255.0;
    }
    // 计算32位浮点数
    if arg == "-f" {
        isFloat = true;
    }
    var newArg = arg
    // TODO: 10进制负数处理？？
    if newArg.last == "L" {
        newArg.removeLast(1)
        while newArg.last == "L" {
            newArg.removeLast(1)
        }
    } else {
        var firstValue: Character
        if arg.components(separatedBy: "x").first == "0" {
            firstValue = newArg.dropFirst(2).first!
        } else {
            newArg = String(arg.drop { $0 == "0" })
            firstValue = newArg.first!
        }
        if negative.contains(firstValue) {
            isNegative = true;
            let index = negative.index(of: firstValue)
            newArg = String(newArg.dropFirst())
            newArg.insert(replace[index!], at: newArg.startIndex)
        }
    }
    
    if newArg.components(separatedBy: "x")[0] == "0" ||
            newArg.last == "h" || newArg.last == "H" {
        
        var result:UInt64 = 0
        Scanner(string: newArg.filter { ($0 != "h") || ($0 != "H")})
                .scanHexInt64(&result)
        print(xmm64(Int(result), isNegative:isNegative) * multiple)
    } else if let result = Int(newArg)  {
        print(xmm64(result, isNegative:isNegative) * multiple)
    }
}
//print(xmm64(0x4041000000000000))
//print(xmm64(0x4020000000000000))
//print(xmm64(4600736089921624345)*255)
//
//print(xmm64(4605380978949069210)*255)
//print(xmm64(4606299360049552605)*255)
//print(xmm64(4607182418800017408)*255)
//
//print(xmm64(4598616748920508818)*255)
//print(xmm64(4607092346807469998)*255)
